#    This file is part of robo-ircbot.
#
#    robo-ircbot is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    robo-ircbot is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with robo-ircbot.  If not, see <http://www.gnu.org/licenses/>.

package Robo::Listener;
use strict;
use warnings;
use threads('exit' => 'threads_only');
use IO::Socket;

# Constructor
sub new
{
        my ($class, $robo, $cfg, $mod, $irc_sock) = @_;
        
        my $self = { };
        
        $self->{robo} = $robo;
        $self->{cfg} = $cfg;
        $self->{mod} = $mod;
        $self->{thread} = undef;
        $self->{sock} = undef;
        $self->{irc_sock} = $irc_sock;
        
        bless($self);
        return $self;
}

# Restart our listener thread.
sub restart
{
        my $self = shift;
        
        if ($self->{cfg}->get_cfg("listener/enabled") ne "yes") { return; }
        
        $self->{robo}->log(":: Restarting listener...");
        
        # Create the thread killer socket.
        my $sock = new IO::Socket::INET(
                PeerAddr => $self->{cfg}->get_cfg("listener/host"),
                PeerPort => $self->{cfg}->get_cfg("listener/port"),
                Proto    => 'tcp'
        );
        if (!$sock) {
                $self->{robo}->log(":: Listener: could not create killer sock!");
                return;
        } else {
                # Send kill command.
                print $sock "l:(".$self->{cfg}->get_cfg("listener/slogin").
                            ")KILL\r\n";
                close($sock);
        }
        
        # Start the listener again.
        $self->start_listening();
}

# Create the main listen socket and start thread.
sub start_listening
{
        my $self = shift;
        
        if ($self->{cfg}->get_cfg("listener/enabled") ne "yes") { return; }
        
        # Create listening socket if it hasn't already been made.
        if (!$self->{sock}) {
                $self->{sock} = new IO::Socket::INET(
                        LocalHost => $self->{cfg}->get_cfg("listener/host"),
                        LocalPort => $self->{cfg}->get_cfg("listener/port"),
                        Proto => 'tcp',
                        Listen => 1,
                        Reuse => 1
                );
                if (!$self->{sock}) {
                        $self->{robo}->log(":: Could not create Listener socket: ".$!);
                        return;
                }
                
                $self->{robo}->log(":: Listener: started.");
        }
        
        # Start the listening thread.
        $self->{thread} = threads->create('listen_thread', $self);
}

# Thread with listen socket inside.
sub listen_thread
{
        my $self = shift;
        $self->{robo}->log(":: Listener: thread started.");
        
        # Put this in any thread you create!
        $SIG{'KILL'} = sub {
                threads->exit() if threads->can('exit');
                exit(0);
        };
        
        while ($self->{sock}) {
                my $new_sock = $self->{sock}->accept();
                $new_sock->autoflush(1);
                my $line;
                
                while (<$new_sock>) {
                        $line = $_;
                        $self->{robo}->log($line);
                        
                        if ($line =~ /^l:\((\S+)\)m:\((\S+)\)\|(.+)\r\n/) {
                                my $login = $1; my $mod = $2; my $send = $3;
                                
                                $self->{robo}->log(":: Listener: login(".
                                                   $login.") mod(".$mod.") -> ".
                                                   $send);
                                
                                # Check that we have a valid login
                                if ($login eq $self->{cfg}->get_cfg("listener/login")) {
                                        $self->{robo}->log(":: Listener: valid login, sending out to modules.");
                                        
                                        # Send to each module wanting this event.
                                        foreach (@{$self->{mod}->{events}->{listener}}) {
                                                eval {
                                                        $self->{mod}->{call}->{$_}->event_listener(
                                                                $self->{robo}, $self->{cfg}, $self->{irc_sock},
                                                                $mod, $send);
                                                };
                                        }
                                }
                        # Kill this sucka.
                        } elsif ($line =~ /^l:\((\S+)\)KILL\r\n/) {
                                # Validate.
                                if ($1 eq $self->{cfg}->get_cfg("listener/slogin")) {
                                        $self->{robo}->log(":: Listener: thread dying!");
                                        #close($self->{sock});
                                        close($new_sock);
                                        threads->exit() if threads->can('exit');
                                        exit(0);
                                }
                        }
                }
        }

        close($self->{sock});
}

1;
